#ifndef _SYS_SOCKET_H
    #define _SYS_SOCKET_H

    #ifdef __cplusplus
    extern "C"
    {
    #endif

    #include <types.h>
    #include <stdint.h>
    #include <arpa/inet.h>
    #include <arpa/ip_addr.h>
    #include <sys/time.h>

    typedef uint32_t socklen_t;

    typedef uint8_t u_char;
    typedef uint16_t u_short;
    typedef uint32_t u_int;
    typedef uint64_t u_long;

    typedef struct sockaddr_in
    {
        u8_t sin_len;
        u8_t sin_family;
        u16_t sin_port;
        struct in_addr sin_addr;
        char sin_zero[8];
    } sockaddr_in_t;

    typedef struct sockaddr
    {
        u8_t sa_len;
        u8_t sa_family;
        char sa_data[14];
    } sockaddr_t;

    typedef struct _sockarg
    {
        void *buff;     //buffer
        int len;        //buffer length
        uint32_t flags; //flags
        sockaddr_t *to_from; //transmit destination
        socklen_t tolen;     //to socket length
        socklen_t *fromlen;  //from socket length
    }_sockarg_t;

    typedef struct linger
    {
         int l_onoff; //option on/off
         int l_linger; //linger time
    }linger_t;

    typedef struct ip_mreg
    {
        in_addr_t imr_multiaddr; //IP multicast address of group
        in_addr_t imr_interface; //local IP address of interface 
    }ip_mreg;

    //socket protocol types (TCP/UDP/RAW)
    #define SOCK_STREAM 1
    #define SOCK_DGRAM 2
    #define SOCK_RAW 3

    //option flags 
    #define SO_DEBUG      0x0001 //turn on debuging into recording
    #define SO_ACCEPTCONN 0x0002 //socket has had listen()
    #define SO_REUSEADDR  0x0004 //allow local address reuse
    #define SO_KEEPALIVE  0x0008 //keep connections alive
    #define SO_DONTROUTE  0x0010 //use interface address
    #define SO_BROADCAST  0x0020 //permit to send and to receive broadcast message 
    #define SO_USELOOPBACK 0x0040 //bypass hardware when possiable 
    #define SO_LINGER     0x0080  //linger on close if data present 
    #define SO_OOBINLINE  0x0100  //leave receive OOB data in line
    #define SO_REUSEPORT  0x0200  //allow local address & port reuse 

    //additional options
    #define SO_SNDBUFF  0x1001 //send buffer size 
    #define SO_RCVBUFF  0x1002 //receive buffer size 
    #define SO_SNDLOWAT 0x1003 //send low-water mark
    #define SO_RCVLOWAT 0x1004 //receive low-water mark
    #define SO_SNDTIMEO 0x1005 //send timeout
    #define SO_RCVTIMEO 0x1006 //receive timeout
    #define SO_ERROR    0x1007 //get error status and clear
    #define SO_TYPE     0x1008 //get socket type
    #define SO_CONTIMEO 0x1009 //connect timeout 
    #define SO_NO_CHECK 0x100a //don't create UDP checksum

    //address family
    #define AF_UNSPEC 0
    #define AF_INET 2
    #define PF_INET AF_INET
    #define PF_UNSPEC AF_UNSPEC

    #define MSG_PEEK 0x01 //peek at an incoming message 
    #define MSG_WAITALL 0x02 //request that the function block until the full amount of data requested can be returned
    #define MSG_OOB     0x04 //request out-of-band data 
    #define MSG_DONTWAIT 0x08 //nonblocking i/of for this operation only 
    #define MSG_NONE 0x10 //sender will send more 

    //ip protocal type
    #define IPPROTO_IP 0
    #define IPPROTO_TCP 6
    #define IPPROTO_UDP 17
    #define IPPROTO_UDPLITE 136

    //options and types for UDP multicast traffic handling
    #define IP_ADDR_MEMBERSHIP 3
    #define IP_DROP_MEMBERSHIP 4
    #define IP_MULTICAST_TTL 5
    #define IP_MULTICAST_IF 6
    #define IP_MULTICAST_LOOP 7

    //options for level IPPROTO_IP
    #define IP_TOS 1
    #define IP_TTL 2

    //options for level IPPROTO_TCP
    #define TCP_NODELAY 0x01   //don't delay send to coclesce packets
    #define TCP_KEEPALIVE 0x02 //send KEEPALIVE probes when idle for pcb->keep_idle milliseconds
    #define TCP_KEEPIDLE 0x03  //set pcb->keep_idle - same as TCP_KEEPALIVE, but use seconds for get/set sockopt
    #define TCP_KEEPINTVL 0x04 //sete pcb->keep_intvl = use seconds for get/set sockopt
    #define TCP_KEEPCNT 0x05   //set pcb->keep_cnt = use number of probes sent for get/set sockopt

    //options for level IPPROTO_UDPLITE
    #define UDPLITE_SEND_CSCOV 0x01 //sender checksum coverage
    #define UDPLITE_RECV_CSCOV 0x02 //minimal receiver checksum coverage 

    #ifndef SHUT_RD
    #define SHUT_RD 0
    #define SHUT_WR 1
    #define SHUT_RDWR
    #endif

    //level number for get/setsockopt() to apply to socket itself 
    #define SOL_SOCKET 0xfff //option for socket level 

    //tyoe of server provider 
    #define IPTOS_TOS_MASK 0x1E
    #define IPTOS_TOS(tos) ((tos)&IPTOS_TOS_MASK)
    #define IPTOS_LOWDELAY 0x10
    #define IPTOS_THROUGHPUT 0x08
    #define IPTOS_RELIABILITY 0x04
    #define IPTOS_LOWCOST 0x02
    #define IPTOS_MINCOST IPTOS_LOWCOST

    //network control precedence desingnation 
    #define IPTOS_PREC_MASK 0xe0 
    #define IPTOS_PREC(tos) ((tos)&IPTOS_PREC_MASK)
    #define IPTOS_PREC_NETCONTROL 0xe0
    #define IPTOS_PREC_INTERNETCONTROL 0xc0
    #define IPTOS_PREC_CRITIC_ECP 0xa0
    #define IPTOS_PREC_FLASHHOVERRIDE 0x80
    #define IPTOS_PREC_FLASH 0x60
    #define IPTOS_PREC_IMMEDIATE 0x40
    #define IPTOS_PREC_PRIORIRY 0x20
    #define IPTOS_PREC_ROUTINE 0x00

    int socket(int domain, int type, int protocol);
    int bind(int sockfd, struct sockaddr *my_addr, int addrlen);
    int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);
    int listen(int sockfd, int backlog);
    int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
    int send(int sockfd, const void *buff, int len, int flags);
    int recv(int sockfd, void *buff, int len, int flags);
    int send_to(int sockfd, const void *buff, int len, int flags, const struct sockaddr *to, socklen_t tolen);
    int recv_from(int sockfd, void *buff, int len, int flags, const struct sockaddr *from, socklen_t fromlen);
    int shutdown(int sockfd, int how);
    int getpeername(int sockfd, struct sockaddr *serv_addr, socklen_t *addrlen);
    int getsockname(int sockfd, struct sockaddr *my_addr, socklen_t *addrlen);
    int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);
    int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);

#ifdef __cplusplus
}
#endif
#endif